GitHub Actionsを使ってコンテナ版AWS Lambdaにデプロイしてみた
本ブログでは、GitHub Actionsを使い、main ブランチへの push をトリガーにコンテナイメージをビルドしてコンテナレジストリのAmazon ECRにプッシュし、AWS Lambdaにコンテナイメージをデプロイする方法を紹介します。
実質的にやっていることは、GitHub の ECS 向けドキュメントをベースに、以下の変更を加えています。
- GitHub から AWS への認証に、IAMアクセスキーの代わりに OpenID Connect(OIDC)を利用
- デプロイ先をAmazon ECSからAWS Lambdaへ変更
大前提として、デプロイのゴールはLambda関数のコンテナイメージを更新することにフォーカスしており、Lambda関数の作成、設定変更、Lambda関数を呼び出すリソースのデプロイは本記事のスコープ外です。
0. GitHub レポジトリにアプリケーションを用意
以下のような階層のLambda関数用レポジトリを用意します。
$ tree -a -I '.git' . ├── .github │ └── workflows │ └── aws-lambda-deploy.yml ├── Dockerfile └── app.py
import sys def handler(event, context): return 'Hello from AWS Lambda using Python' + sys.version + '!'
FROM public.ecr.aws/lambda/python:3.9 COPY app.py ${LAMBDA_TASK_ROOT} CMD [ "app.handler" ]
.github/workflows/aws-lambda-deploy.yml
が GitHub Actionsのワークフロー用設定ファイルです。
具体的な内容は ステップ4 で解説しています。
1. Amazon ECR レポジトリの作成
コンテナレジストリ Amazon ECR にレポジトリを作成します。
2. AWS Lambda 関数の作成
ウォークスルー手順簡易化のため、コンテナ版AWS Lambda関数を事前に作成します。
さらに、コンテナイメージURIには既存の URI を指定しておきます。
3. AWS側で OIDC 設定
GitHubからAWSリソースを操作する際に、OIDCで取得した一時トークンを利用します。
AWS側では
- アイデンティティプロバイダー
- GitHubのOIDCがAssumeするIAMロール
を作成します。
これらリソースは各AWSアカウントごとに一つ用意します。
参考 : Configuring OpenID Connect in Amazon Web Services - GitHub Docs
アイデンティティプロバイダー
IAM→アイデンティティプロバイダーから作成します。
以下を指定します。
- Provider type : OpenID Connect
- Provider URL : https://token.actions.githubusercontent.com
- Audience : sts.amazonaws.com
作成されたリソースの ARN を控えます。
IAM ロール
GitHub アクション aws-actions/configure-aws-credentials の GitHub ページに、IAM ロールを作成するCloudFormationテンプレートが用意されています。
このテンプレートを流して、リソース作成します。
スタック作成時に以下を指定します。
- GitHub 組織名
- 先程作成したOIDCプロバイダーのARN
- GitHub レポジトリ名
なお、現時点の CloudFormation テンプレートは以下の通りです。
Parameters: GitHubOrg: Type: String RepositoryName: Type: String OIDCProviderArn: Description: Arn for the GitHub OIDC Provider. Default: "" Type: String Conditions: CreateOIDCProvider: !Equals - !Ref OIDCProviderArn - "" Resources: Role: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Action: sts:AssumeRoleWithWebIdentity Principal: Federated: !If - CreateOIDCProvider - !Ref GithubOidc - !Ref OIDCProviderArn Condition: StringLike: token.actions.githubusercontent.com:sub: !Sub repo:${GitHubOrg}/${RepositoryName}:* GithubOidc: Type: AWS::IAM::OIDCProvider Condition: CreateOIDCProvider Properties: Url: https://token.actions.githubusercontent.com ClientIdList: - sts.amazonaws.com ThumbprintList: - a031c46782e6e6c662c2c87c76da9aa62ccabd8e Outputs: Role: Value: !GetAtt Role.Arn
作成された IAMロールには、ポリシーを追加します。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "ECR", "Effect": "Allow", "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:CompleteLayerUpload", "ecr:InitiateLayerUpload", "ecr:PutImage", "ecr:UploadLayerPart" ], "Resource": "*" }, { "Sid": "Lambda", "Effect": "Allow", "Action": "lambda:UpdateFunctionCode", "Resource": "*" } ] }
許可するActionは要件に合わせて調整してください。
4. GitHub Actions ワークフローを作成
Lambda関数のレポジトリに Lambda デプロイ用のワークフローを追加します。
ファイル冒頭の env
ブロックで定義している変数を環境に合わせて調整してください。
name: Deploy container image to AWS Lambda on: push: branches: - main env: AWS_ACCOUNT_ID: MY_ACCOUNT_ID AWS_ROLE_NAME: MY_ROLE_NAME AWS_ROLE_SESSION_NAME: MY_ROLE_SESSION_NAME AWS_REGION: us-west-1 ECR_REPOSITORY: MY_REPOSITORY_NAME LAMBDA_FUNCTION_NAME: MY_FUNCTION_NAME permissions: id-token: write contents: read jobs: aws-deploy: name: Push to ECR runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@master with: role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/${{ env.AWS_ROLE_NAME }} role-session-name: ${{ env.AWS_ROLE_SESSION_NAME }} aws-region: ${{ env.AWS_REGION }} - name: Login to Amazon ECR id: login-ecr uses: aws-actions/amazon-ecr-login@v1 - name: Build, tag, and push image to Amazon ECR id: build-image env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} IMAGE_TAG: ${{ github.sha }} run: | # Build a docker container and # push it to ECR so that it can # be deployed to Lambda. docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG # Update Lambda configuration aws lambda update-function-code --function-name $LAMBDA_FUNCTION_NAME --image-uri $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
ポイントは以下です。
- アクション
aws-actions/configure-aws-credentials
でOIDCトークンを取得 - アクション
aws-actions/amazon-ecr-login
で ECR にログイン - Gitのコミットハッシュ値をイメージタグ(
IMAGE_TAG
)に利用
最後のステップでは API aws lambda update-function-code
を直接呼び出してLambda関数のイメージだけを更新しています。
AWS CDK 等を利用すると、Lambda 関数を使ったサービス全般のデプロイが可能です。
5. 動作確認
GitHub の main ブランチに更新が走ると、今回登録したワークフローが実行されることを確認してください。
GitHub 側でワークフローの実行が成功し、AWS 側で以下を確認できればOKです。
- ECR に新しいイメージのPUSHされている
- Lambda 関数のコンテナイメージが最新のものに変更されている
最後に
AWS Lambdaのコンテナイメージ対応により、CI/CDパイプラインを構築しやすくなりました。
本ブログでは、その一例として、GitHub ActionsとOpenID Connect(OIDC)を利用し、mainブランチへの更新をトリガーに、コンテナLambdaへデプロイする方法を紹介しました。
お使いのLambdaにピッタリなCI/CD環境を構築し、Lambdaの開発サイクルを加速させちゃいましょう!
参考
- GitHub Actions OIDCでconfigure-aws-credentialsでAssumeRoleする | DevelopersIO
- Deploying to Amazon Elastic Container Service - GitHub Docs
- Configuring OpenID Connect in Amazon Web Services - GitHub Docs
- GitHub - aws-actions/configure-aws-credentials: Configure AWS credential environment variables for use in other GitHub Actions.